﻿using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Windows.Forms;
class GlobalKeyHook
{
    #region Constant, Structure and Delegate Definitions

    delegate int keyboardHookProc(int code, int wParam, ref keyboardHookStruct lParam);
    keyboardHookProc khp; 

    public struct keyboardHookStruct
    {
        public int vkCode;
        public int scanCode;
        public int flags;
        public int time;
        public int dwExtraInfo;
    }

    const int WH_KEYBOARD_LL = 13;
    const int WM_KEYDOWN = 0x100;
    const int WM_KEYUP = 0x101;
    const int WM_SYSKEYDOWN = 0x104;
    const int WM_SYSKEYUP = 0x105;
    #endregion

    #region Instance Variables

    public List<Keys> HookedKeys = new List<Keys>();
    IntPtr hhook = IntPtr.Zero;

    #endregion

    #region Events

    public delegate void ScanCodeHandler(ushort scanCode, bool keyDown);
    public event ScanCodeHandler ScanCode;

    #endregion

    #region Constructors and Destructors

    [DllImport("user32", EntryPoint = "MapVirtualKeyEx")]
    public static extern int MapVirtualKeyEx(int uCode, int uMapType, int dwhkl);

    public static Keys GetKeyFromScanCode(ushort scan)
    {
        return (Keys)MapVirtualKeyEx(scan, 1, 0);
    }

    public GlobalKeyHook()
    {
        khp = new keyboardHookProc(hookProc);
    }

    ~GlobalKeyHook()
    {
        unhook();
    }

    #endregion

    #region Public Methods

    public void hook()
    {
        IntPtr hInstance = LoadLibrary("User32");
        hhook = SetWindowsHookEx(WH_KEYBOARD_LL, khp, hInstance, 0);
    }

    public void unhook()
    {
        UnhookWindowsHookEx(hhook);
    }

    int hookProc(int code, int wParam, ref keyboardHookStruct lParam)
    {
        if (code >= 0)
        {
            ScanCode((ushort)lParam.scanCode, (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN));
            if (new KeyEventArgs((Keys)lParam.vkCode).Handled) return 1;
        }
        return CallNextHookEx(hhook, code, wParam, ref lParam);
    }
    #endregion

    #region DLL imports

    [DllImport("user32.dll")]
    static extern IntPtr SetWindowsHookEx(int idHook, keyboardHookProc callback, IntPtr hInstance, uint threadId);

    [DllImport("user32.dll")]
    static extern bool UnhookWindowsHookEx(IntPtr hInstance);

    [DllImport("user32.dll")]
    static extern int CallNextHookEx(IntPtr idHook, int nCode, int wParam, ref keyboardHookStruct lParam);

    [DllImport("kernel32.dll")]
    static extern IntPtr LoadLibrary(string lpFileName);
    #endregion
}
